[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Usually vbcc
will be called by vc
. However, if called
directly it expects the following syntax:
|
The following options are supported by the machine independent part
of vbcc
(and will be passed through by vc
):
See section 3.4.13 Unused Object Elimination.
Usually DWARF2-output will be generated by default, if possible.
Also, options regarding optimization and code-generation may affect the debug output (see section 3.4.19 Debugging Optimized Code).
inline
function-specifier
restrict
-qualifier
//
-comments
_Pragma
vbcc
.
By default, these optimizations will also be performed
on inline-assembly code of the application. This switch
turns off this behaviour. See section 3.5.3 Inline-Assembly Functions.
(a+b)+c==a+(b+c)
is not true for all
floating point numbers a
,b
,c
. Therefore
certain optimizations
depending on this property cannot be performed on floating
point numbers.
This option tells vbcc
to treat floating point
operations as associative and perform those optimizations
even if that may change the results in some cases (not
ISO conforming).
vbcc
will try to use them when optimizing.
This flag prevents vbcc
from using them.
This generates less efficient code but some broken code (e.g. code which calls varargs functions without correct prototypes in scope) may work.
vbcc
keeps all data of initializations in memory
during the whole compilation (it can sometimes make use
of this when optimizing). This can take some amount of
memory, though. This options tells vbcc
to
keep as little of this data in memory as possible.
This has not yet been tested very well.
The assembler output will be saved to `file.asm' (if `file' already contained a suffix, this will first be removed; same applies to .ic1/.ic2)
vbcc
knows the following kinds of messages:
vbcc
will abort.
E.g. no source file or really corrupt source.
vbcc
cannot generate useful
code. Compilation continues, but no code will be
generated.
E.g. unknown identifiers.
vbcc
will generate code that
could be what you want (or not).
E.g. missing semicolon.
Errors or the first kind of warnings are always displayed and cannot be suppressed.
Only some warnings of the second kind are turned on by default. Many of them are very useful for some but annoying to others, and their usability may depend on programming style. Everybody is recommended to find their own preferences.
A good way to do this is starting with all warnings turned on by `-warn=-1'. Now all possible warnings will be issued. Everytime a warning that is not considered useful appears, turn that one off with `-dontwarn=n'.
See 8. List of Errors for a list of all diagnostic messages available.
See 2. The Frontend to find out how to configure vc
to your
preferences.
vbcc
can handle the following atomic data types:
signed char
unsigned char
signed short
unsigned short
signed int
unsigned int
signed long int
unsigned long int
signed long long int
unsigned long long int
float
double
long double
The default signedness for integer types is signed
.
Depending on the backend, some of these types can have identical
representation. The representation (size, alignment etc.) of these types
usually varies between different backends. vbcc
is able to support
arbitrary implementations.
Backends may be restricted and omit some types (e.g. floating point on small embedded architectures) or offer additional types. E.g. some backends may provide special bit types or different pointer types.
vbcc
offers different levels of optimization, ranging from fast
compilation with straight-forward code suitable for easy debugging
to highly aggressive cross-module optimizations delivering very
fast and/or tight code.
This section describes the general phases of compilation and gives a short overview on the available optimizations.
In the first compilation phase every function is parsed into a tree structure one expression after the other. Type-checking and some minor optimizations like constant-folding or some algebraic simplifications are done on the trees. This phase of the translation is identical in optimizing and non-optimizing compilation.
Then intermediate code is generated from the trees. In non-optimizing compilation temporaries needed to evaluate the expression are immediately assigned to registers while in optimizing compilation, a new variable is generated for each temporary. Slightly different intermediate code is produced in optimizing compilation. Some minor optimizations are performed while generating the intermediate code (simple elimination of unreachable code, some optimizations on branches etc.).
After intermediate code for the whole function has been generated, simple register allocation may be done in non-optimizing compilation if bit 1 has been set in the `-O' option. Afterwards, the intermediate code is passed to the code generator and then all memory for the function, its variables etc. is freed.
In optimizing compilation flowgraphs are constructed, data flow analysis is performed and many passes are made over the function's intermediate code. Code may be moved around, new variables may be added, other variables removed etc. etc. (for more detailed information on the optimizations look at the description for the `-O' option below).
Many of the optimization routines depend on each other. If one
routine finds an optimization, this often enables other routines to
find further ones. Also, some routines only do a first step and let
other routines 'clean up' afterwards. Therefore vbcc
usually
makes many passes until no further optimizations are found.
To avoid possible extremely long optimization times, the number of
those passes can be limited with `-maxoptpasses' (the
default is max. 10 passes).
vbcc
will display a warning if more passes might be useful.
Depending on the optimization level, a whole translation-unit or even several translation-units will be read at once. Also, the intermediate code for all functions may be kept in memory during the entire compilation. Be aware that higher optimization levels can take much more time and memory to complete.
The following table lists the optimizations which are activated by
bits in the argument of the `-O' option. Note that not all
combinations are valid. It is heavily recommended not to fiddle with
this option but just use one of the settings provided by vc
(e.g. `-O0' - `-O4'). These options also automatically
handle actions like invoking the scheduler or cross-module optimizer.
vbcc
will try to identify loops and perform some loop optimizations.
See 3.4.8 Strength Reduction and 3.4.7 Loop-Invariant Code Motion.
These only work if bit 5 (32) is set.
vbcc
tries to place variables at the same memory addresses if possible
(see 3.4.13 Unused Object Elimination).
Also, vbcc
tries to place global/static variables and variables which
have their address taken in registers, if possible
(see section 3.4.1 Register Allocation).
Also look at the documentation for the target-dependent part of vbcc
.
There may be additional machine specific optimization options.
This optimization tries to assign variables or temporaries into machine registers to save time and space. The scope and details of this optimization vary on the optimization level.
With `-O0' only temporaries during expression-evaluation are put into registers. This may be useful for debugging.
At the default level (without the optimizer), additionally local variables whose address has not been taken may be put into registers for a whole function. The decision which variables to assign to registers is based on very simple heuristics.
In optimizing compilation a different algorithm will be used which uses hierarchical live-range-splitting. This means that variables may be assigned to different registers at different time. This typically allows to put the most used variables into registers in all inner loops. Note that this means that a variable can be located in different registers at different locations. Most debuggers can not handle this.
Also, the use of registers can be guided by information provided by the backend, if available. For architectures which are not very orthogonal this allows to choose registers which are better suited to certain operations. Constants can also be assigned to registers, if this is beneficial for the architecture.
The options `-speed' and `-size' change the behaviour of the register-allocator to optimize for speed or size of the generated code.
On low optimization levels, only local variables whose address has not
been taken will be assigned to registers. On higher optimization levels,
vbcc
will also try to assign global/static variables and variables which
had their address taken, to registers. Typically, this occurs during
loops. The variables will be loaded into a register before entering a loop
and stored back after the loop. However, this can only be done if vbcc
can detect that the variable is not modified in unpredictable ways.
Therefore, alias-analysis is crucial for this optimization.
During register-allocation vbcc
will use information on
register usage of functions to minimize loading/saving of registers between
function-calls. Therefore, other optimizations will affect register
allocation.
See 3.4.14 Alias Analysis, 3.4.15 Inter-Procedural Analysis and
3.4.16 Cross-Module Optimizations.
When optimizing vbcc
will construct a flowgraph for every function and
perform optimizations based on control-flow. For example, code which is
unreachable will be removed and branches to other branches or branches
around branches will be simplified.
Also, unused labels will be removed and basic blocks united to allow further optimizations.
For example, the following code
void f(int x, int y) { if(x > y) goto label1; q(); label1: goto label2; r(); label2: } |
will be optimized like:
void f(int x, int y) { if(x <= y) q(); } |
Identical code at the beginning or end of basic blocks will be moved to the successors/predecessors under certain conditions.
If an expression has been computed on all paths leading to a second
evaluation and vbcc
knows that the operands have not been changed,
then the result of the original evaluation will be reused instead of
recomputing it. Also, memory operands will be loaded into registers and
reused instead of being reloaded, if possible.
For example, the following code
void f(int x, int y) { q(x * y, x * y); } |
will be optimized like:
void f(int x, int y) { int tmp; tmp = x * y; q(tmp, tmp); } |
Depending on the optimization level, vbcc
will perform this optimization
only locally within basic blocks or globally across an entire function.
As this optimization requires detecting whether operand of an expression may have changed, it will be affected by other optimizations. See 3.4.14 Alias Analysis, 3.4.15 Inter-Procedural Analysis and 3.4.16 Cross-Module Optimizations.
If a variable is assigned to another one, the original variable will be used as long as it is not modified. This is especially useful in conjunction with other optimizations, e.g. common subexpression elimination.
For example, the following code
int y; int f() { int x; x = y; return x; } |
will be optimized like:
int y; int f() { return y; } |
Depending on the optimization level, vbcc
will perform this optimization
only locally within basic blocks or globally across an entire function.
As this optimization requires detecting whether a variable may have changed, it will be affected by other optimizations. See 3.4.14 Alias Analysis, 3.4.15 Inter-Procedural Analysis and 3.4.16 Cross-Module Optimizations.
If a variable is known to have a constant value (this includes addresses of objects) at some use, it will be replaced by the constant.
For example, the following code
int f() { int x; x = 1; return x; } |
will be optimized like:
int f() { return 1; } |
Depending on the optimization level, vbcc
will perform this optimization
only locally within basic blocks or globally across an entire function.
As this optimization requires detecting whether a variable may have changed, it will be affected by other optimizations. See 3.4.14 Alias Analysis, 3.4.15 Inter-Procedural Analysis and 3.4.16 Cross-Module Optimizations.
If a variable is assigned a value which is never used (either because it is overwritten or its lifetime ends), the assignment will be removed. This optimization is crucial to remove code which has become dead due to other optimizations.
For example, the following code
int x; void f() { int y; x = 1; y = 2; x = 3; } |
will be optimized like:
int x; void f() { x = 3; } |
As this optimization requires detecting whether a variable may be read, it will be affected by other optimizations. See 3.4.14 Alias Analysis, 3.4.15 Inter-Procedural Analysis and 3.4.16 Cross-Module Optimizations.
If the operands of a computation within a loop will not change during iterations, the computation will be moved outside of the loop.
For example, the following code
void f(int x, int y) { int i; for (i = 0; i < 100; i++) q(x * y); } |
will be optimized like:
void f(int x, int y) { int i, tmp = x * y; for (i = 0; i < 100; i++) q(tmp); } |
As this optimization requires detecting whether operands of an expression may have changed, it will be affected by other optimizations. See 3.4.14 Alias Analysis, 3.4.15 Inter-Procedural Analysis and 3.4.16 Cross-Module Optimizations.
This is an optimization applied to loops in order to replace more costly operations (usually multiplications) by cheaper ones (typically additions). Linear functions of an induction variable (a variable which is changed by a loop-invariant value in every iteration) will be replaced by new induction variables. If possible, the original induction variable will be eliminated.
As array accesses are actually composed of multiplications and additions, they often benefit significantly by this optimization.
For example, the following code
void f(int *p) { int i; for (i = 0; i < 100; i++) p[i] = i; } |
will be optimized like:
void f(int *p) { int i; for (i = 0; i < 100; i++) *p++ = i; } |
As this optimization requires detecting whether operands of an expression may have changed, it will be affected by other optimizations. See 3.4.14 Alias Analysis, 3.4.15 Inter-Procedural Analysis and 3.4.16 Cross-Module Optimizations.
If an induction variable is only used to determine the number of iterations through the loop, it will be removed. Instead, a new variable will be created which counts down to zero. This is generally faster and often enables special decrement-and-branch or decrement-and-compare instructions.
For example, the following code
void f(int n) { int i; for (i = 0; i < n; i++) puts("hello"); } |
will be optimized like:
void f(int n) { int tmp; for(tmp = n; tmp > 0; tmp--) puts("hello"); } |
As this optimization requires detecting whether operands of an expression may have changed, it will be affected by other optimizations. See 3.4.14 Alias Analysis, 3.4.15 Inter-Procedural Analysis and 3.4.16 Cross-Module Optimizations.
vbcc
reduces the loop overhead by replicating the loop body
and reducing the number of iterations. Also, additional optimizations between
different iterations of the loop will often be enabled by creating larger
basic blocks. However, code-size as well as compilation-times can
increase significantly.
This optimization can be controlled by `-unroll-size' and
`-unroll-all'. `-unroll-size' specifies the maximum number
of intermediate instructions for the unrolled loop body. vbcc
will try
to unroll the loop as many times to suit this value.
If the number of iterations is constant and the size of the loop body multiplied by this number is less or equal to the value specified by `-unroll-size', the loop will be unrolled completely. If the loop is known to be executed exactly once, it will always be unrolled completely.
For example, the following code
void f() { int i; for (i = 0; i < 4; i++) q(i); } |
will be optimized like:
void f() { q(0); q(1); q(2); q(3); } |
If the number of iteration is constant the loop will be unrolled as many times as permitted by the size of the loop and `-unroll-size'. If the number of iterations is not a multiple of the number of replications, the remaining iterations will be unrolled separately.
For example, the following code
void f() { int i; for (i = 0; i < 102; i++) q(i); } |
will be optimized like:
void f() { int i; q(0); q(1); for(i = 2; i < 102;){ q(i++); q(i++); q(i++); q(i++); } } |
By default, only loops with a constant number of iterations will be
unrolled. However, if `-unroll-all' is specified, vbcc
will also
unroll loops if the number of iterations can be calculated at entry to
the loop.
For example, the following code
void f(int n) { int i; for (i = 0; i < n; i++) q(i); } |
will be optimized like:
void f(int n) { int i, tmp; i = 0; tmp = n & 3; switch(tmp){ case 3: q(i++); case 2: q(i++); case 1: q(i++); } while(i < n){ q(i++); q(i++); q(i++); q(i++); } } |
As this optimization requires detecting whether operands of an expression may have changed, it will be affected by other optimizations. See 3.4.14 Alias Analysis, 3.4.15 Inter-Procedural Analysis and 3.4.16 Cross-Module Optimizations.
To reduce the overhead, a function call can be expanded inline. Passing parameters can be optimized as the arguments can be directly accessed by the inlined function. Also, further optimizations are enabled, e.g. constant arguments can be evaluated or common subexpressions between the caller and the callee can be eliminated. An inlined function call is as fast as a macro. However (just as with using large macros), code size and compilation time can increase significantly.
Therefore, this optimization can be controlled with `-inline-size' and
`-inline-depth'. vbcc
will only inline functions which contain
less intermediate instructions than specified with this option.
For example, the following code
int f(int n) { return q(&n,1); } void q(int *x, int y) { if(y > 0) *x = *x + y; else abort(); } |
will be optimized like:
int f(int n) { return n + 1; } void q(int *x, int y) { if(y > 0) *x = *x + y; else abort(); } |
If a function to be inlined calls another function, that function can also be inlined. This also includes a recursive call of the function.
For example, the following code
int f(int n) { if(n < 2) return 1; else return f(n - 1) + f(n - 2); } |
will be optimized like:
int f(int n) { if(n < 2) return 1; else{ int tmp1 = n - 1, tmp2, tmp3 = n - 2, tmp4; if(tmp1 < 2) tmp2 = 1; else tmp2 = f(tmp1 - 1) + f(tmp2 - 2); if(tmp3 < 2) tmp4 = 1; else tmp4 = f(tmp3 - 1) + f(tmp3 - 2); return tmp2 + tmp4; } } |
By default, only one level of inlining is done. The maximum nesting of inlining can be set with `-inline-depth'. However, this option should be used with care. The code-size can increase very fast and in many cases the code will be slower. Only use it for fine-tuning after measuring if it is really beneficial.
At lower optimization levels a function must be defined in the same
translation-unit as the caller to be inlined. With cross-module
optimizations, vbcc
will also inline functions which are defined in
other files. See section 3.4.16 Cross-Module Optimizations.
See also 3.5.3 Inline-Assembly Functions.
This optimization will replace calls to some known functions
(usually library functions) with calls to different functions or
special inline-code. This optimization usually depends on the
arguments to a function. Typical candidates are the printf
family of functions and string-functions applied to string-literals.
For example, the following code
int f() { return strlen("vbcc"); } |
will be optimized like:
int f() { return 4; } |
Note that there are also other possibilities of providing specially optimized library functions. See 3.5.3 Inline-Assembly Functions and 3.4.11 Function Inlining.
Depending on the optimization level, vbcc
will try to eliminate different
objects and reduce the size needed for objects.
Generally, vbcc
will try to use common storage for local non-static variables
with non-overlapping live-ranges .
At some optimization levels and with `-size' specified, vbcc
will try to
order the placement of variables with static storage-duration to minimize
padding needed due to different alignment requirements. This optimization
generally benefits from an increased scope of optimization.
See section 3.4.16 Cross-Module Optimizations.
At higher optimization levels objects and functions which are not referenced are eliminated. This includes functions which have always been inlined or variables which have always been replaced by constants.
When using separate compilation, objects and functions with external linkage usually cannot be eliminated, because they might be referenced from other translation-units. This precludes also elimination of anything referenced by such an object or function.
However, unused objects and functions with
external linkage can be eliminated if `-final' is specified.
In this case vbcc
will assume that basically the entire program is presented
and eliminate everything which is not referenced directly or indirectly
from main(). If some objects are not referenced but must not be
eliminated, they have to be declared with the __entry
attribute.
Typical examples are callback functions which are called from a library
function or from anywhere outside the program, interrupt-handlers or
other data which should be preserved.
See section 3.4.16 Cross-Module Optimizations.
Many optimizations can only be done if it is known that two expressions are not aliased, i.e. they do not refer to the same object. If such information is not available, worst-case assumptions have to be made in order to create correct code. In the C language aliasing can occur by use of pointers. As pointers are generally a very frequently used feature of C and also array accesses are just disguised pointer arithmetic, alias analysis is very important.
vbcc
uses the following methods to obtain aliasing information:
p1
and p2
must not point to the same object:
f(int *p1, long *p2) { ... } |
vbcc
will assume that the source is correct and does not break
this requirement of the C language. If a program does break this
requirement and cannot be fixed, then -no-alias-opt
must be
specified and some performance will be lost.
vbcc
will try to keep track of all
objects a pointer can point to. In the following example, vbcc
will see that p1
can only point to x
or y
whereas p2
can only point to z
. Therefore it
knows that p1
and p2
are not aliased.
int x[10], y[10], z[10]; int f(int a, int b, int c) { int *p1, *p2; if(a < b) p1 = &x[a]; else p1 = &y[b]; p2 = &z[c]; ... } |
As pointers itself may be aliased and function calls might modify pointers, this analysis sometimes benefits from a larger scope of optimization. See 3.4.15 Inter-Procedural Analysis and 3.4.16 Cross-Module Optimizations.
This optimization will alter the behaviour of broken code which uses pointer arithmetic to step from one object into another.
restrict
-qualifier to help
alias analysis. If a pointer is declared with this qualifier, the
compiler may assume that the object pointed to by this pointer is
only aliased by pointers which are derived from this pointer.
For a formal definition of the rules for restrict
please
consult ISO/IEC9899:1999.
vbcc
will make use of this information at higher optimization
levels (`-c99' must be used to use this new keyword).
A very useful application for restrict
are function
parameters. Consider the following example:
void cross_prod(float *restrict res, float *restrict x, float restrict *y) { res[0] = x[1] * y[2] - x[2] * y[1]; res[0] = x[2] * y[0] - x[0] * y[2]; res[0] = x[0] * y[1] - x[1] * y[0]; } |
Without restrict
, a compiler has to assume that writing the
results through res
can modify the object pointed to by
x
and y
. Therefore, the compiler has to reload all
the values on the right side twice. With restrict
vbcc
will optimize this code like:
void cross_prod(float *restrict res, float *restrict x, float restrict *y) { float x0 = x[0], x1 = x[1], x2 = x[2]; float y0 = y[0], y1 = x[1], y2 = y[2]; res[0] = x1 * y2 - x2 * y1; res[0] = x2 * y0 - x0 * y2; res[0] = x0 * y1 - x1 * y0; } |
Apart from the number of different optimizations a compiler offers, another important point is the scope of the underlying analysis. If a compiler only looks at small parts of code when deciding whether to do an optimization, it often cannot prove that a transformation does not change the behaviour and therefore has to reject it.
Simple compilers only look at single expressions, simple optimizing compilers often restrict their analysis to basic blocks or extended basic blocks. Analyzing a whole function is common in today's optimizing compilers.
This already allows many optimizations but often worst-case assumptions
have to be made when a function is called.
To avoid this, vbcc
will not restrict its analysis to single functions
at higher optimization levels. Inter-procedural data-flow analysis often
allows for example to eliminate more common subexpressions or dead code.
Register allocation and many other optimizations also sometimes benefit
from inter-procedural analysis.
Further extension of the scope of optimizations is possible by activating cross-module optimizations. See section 3.4.16 Cross-Module Optimizations.
Separate compilation has always been an important feature of the C language. Splitting up an application into several modules does not only reduce turn-around times and resource-requirements for compilation, but it also helps writing reusable well-structured code.
However, an optimizer has much more possibilities when it has access to the
entire source code. In order to provide maximum possible optimizations
without sacrificing structure and modularity of code, vbcc
can do
optimizations across different translation-units. Another benefit is
that cross-module analysis also will detect objects which are declared
inconsistently in different translation-units.
Unfortunately common object-code does not contain enough information to
perform aggressive optimization, To overcome this problem, vbcc
offers
two solutions:
vbcc
, it will read in all files at once, perform
optimizations across these files and generate a single object
file as output. This file is similar to what would have been
obtained by separately compiling the files and linking the
resulting objects together.
vbcc
also provides means
to generate some kind of special pseudo object files which pretain
enough high-level information to perform aggressive optimizations
at link time.
If `-wpo' is specified (which will automatically be done by
vc
at higher optimization levels) vbcc
will generate such files
rather than normal assembly or object files. These files can
not be handled by normal linkers. However, vc
will detect these
files and before linking it will pass all such files to vbcc
again.
vbcc
will optimize the entire code and generate real code which
is then passed to the linker.
It is possible to pass vc
a mixture of real and pseudo object
files. vc
will detect the pseudo objects, compile them and link
them together with the real objects. Obviously, vc
has to be used
for linking. Directly calling the linker with pseudo objects will
not work.
Please note that optimization and code generation is deferred to link-time. Therefore, all compiler options related to optimization and code generation have to be specified at the linker command as well. Otherwise they would be ignored. Other options (e.g. setting paths or defining macros) have to be specified when compiling.
Also, turn-around times will obviously increase as usually everything will be rebuild even if makefiles are used. While only the corresponding pseudo object may be rebuilt if one file is changed, all the real work will be done at the linking stage.
Some backends provide an instruction scheduler which is automatically run
by vc
at higher optimization levels. The purpose is to reorder
instructions to make better use of the different pipelines a CPU may
offer.
The exact details depend heavily on the backend, but in general the scheduler will try to place instructions which can be executed in parallel (e.g. on super-scalar architectures) close to each other. Also, instructions which depend on the result of another instruction will be moved further apart to avoid pipeline-stalls.
Please note that it may be crucial to specify the correct derivate of a CPU family in order to get best results from the sceduler. Different variants of an architecture may have a different number and behaviour of pipelines requiring different scheduling decisions.
Consult the backend documentation for details.
In addition to those optimzations which are available for all targets, every backend will provide a series of additional optimizations. These vary between the different backends, but optimizations frequently done by backends are:
Debugging of optimized code is usually not possible without problems.
Many compilers turn off almost all optimizations when debugging.
vbcc
allows debugging output together with optimizations and
tries to still do all optimizations (some restrictions have to be made
regarding instruction-scheduling).
However, depending on the debugger and debugging-format used, the information displayed in the debugger may differ from the real situation. Typical problems are:
When optimizing vbcc will often remove certain variables or eliminate code which sets them. Sometimes it is possible, to tell the debugger that a variable has been optimized away, but most of the time the debugger does not allow this and you will just get bogus values when trying to inspect a variable.
Also, variables whose locations differs at various locations of the program (e.g. a variable is in a register at one place and in memory at another) can only be correctly displayed, if the debugger supports this.
Sometimes, this can even occur in non-optimized code (e.g. with register-parameters or a changing stack-pointer).
When stepping through a program, you may see lines of code be executed out-of-order or parts of the code skipped. This often occurs due to code being moved around or eliminated/combined.
Setting break-points (especially on source-lines) needs some care when optimized code is debugged. E.g. code may have been moved or even replicated at different parts. A break-point set in a debugger will usually only be set on one instance of the code. Therefore, a different instance of the code may have been executed although the break-point was not hit.
This section lists and describes all extensions to the C language provided
by vbcc
. Most of them are implemented in a way which does not break
correct C code and still allows all diagnostics required by the C standard
by using reserved identifiers.
The only exception (see section 3.5.3 Inline-Assembly Functions) can be turned off using `-iso' or `-ansi'.
vbcc
accepts the following #pragma
-directives:
#pragma printflike <function>
#pragma scanflike <function>
vbcc
will handle <function>
specially.
<function>
has to be an already declared
function, with external linkage, that
takes a variable number of arguments
and a const char *
as the last fixed
parameter.
If such a function is called with a
string-constant as format-string, vbcc
will check if the arguments seem to
match the format-specifiers in the
format-string, according to the rules
of printf or scanf.
Also, vbcc
will replace the call by a
call to a simplified version according
to the following rules, if such a
function has been declared with external
linkage:
__v0<function>
will be called.
d,i,x,X,o,s,c
are used, __v1<function>
will be called.
__v2<function>
will be called.
#pragma dontwarn <n>
#pragma popwarn
.
#pragma warn <n>
#pragma popwarn
.
pragma popwarn
#pragma warn
or
#pragma dontwarn
.
#pragma only-inline on
Do not use this with functions that have local static variables!
#pragma only-inline off
#pragma opt <n>
#pragma begin_header
#pragma end_header
. Not for use in applications!
#pragma end_header
#pragma begin_header
. Marks the end
of a system-header. Not for use in applications!
If the parameters for certain functions should be passed in certain
registers, it is possible to specify the registers using
__reg("<reg>")
in the
prototype, e.g.
void f(__reg("d0") int x, __reg("a0") char *y) { ... } |
The names of the available registers depend on the backend and will be listed in the corresponding part of the documentation. Note that a matching prototype must be in scope when calling such a function - otherwise wrong code will be generated. Therefore it is not useful to use register parameters in an old-style function-definition.
If the backend cannot handle the specified register for a certain type, this will cause an error. Note that this may happen although the register could store that type, if the backend does not provide the necessary support.
Also note that this may force vbcc
to create worse code.
Only use them if you know what you are doing!
A function-declaration may be followed by '=' and a string-constant. If a function is called with such a declaration in scope, no function-call will be generated but the string-constant will be inserted in the assembly-output. Otherwise the compiler and optimizer will treat this like a function-call, i.e. the inline-assembly must not modify any callee-save registers without restoring them. However, it is also possible to specify the side-effects of inline-assembly functions like registers used or variables used and modified (see section 3.5.9 Specifying side-effects).
Example:
double sin(__reg("fp0") double) = "\tfsin.x\tfp0\n"; |
There are several issues to take care of when writing inline-assembly.
vbcc
assumes that inline-assembly does not introduce any new
control-flow edges. I.e. control will only enter inline-assembly
if the function call is reached and if control leaves
inline-assembly it will continue after the call.
Inline-assembly-functions are not recognized when ANSI/ISO mode is turned on.
vbcc
offers attributes to variables or functions. These attributes
can be specified at the declaration of a variable or function and
are syntactically similar to storage-class-specifiers
(e.g. static
).
Often, these attributes are specific to one backend and will be
documented in the backend-documentation (typical attributes would
e.g. be __interrupt
or __section
). Attributes may
also have parameters. A generally available
attribute s __entry
which is used to preserve unreferenced
objects and functions (see section 3.4.13 Unused Object Elimination):
__entry __interrupt __section("vectab") void my_handler() |
Additional non-target-specific attributes are available to specify side-effects of functions (see section 3.5.9 Specifying side-effects).
Please note that some common extensions like __far
are
variable attributes on some architectures, but actually type
attributes (see section 3.5.5 Type Attributes) on others. This is due to
significantly different meanings on different architectures.
Types may be qualified by additional attributes, e.g. __far
,
on some backends. Regarding the availability of type attributes
please consult the backend documentation.
Syntactically type attributes have to be placed like a type-qualifier
(e.g. const
).
As example, some backends know the attribute __far
.
Declaration of a pointer to a far-qualified character would be
__far char *p; |
whereas
char * __far p; |
is a far-qualified pointer to an unqualified char.
Please note that some common extensions like __far
are
type attributes on some architectures, but actually variable
attributes (see section 3.5.4 Variable Attributes) on others. This is due to
significantly different meanings on different architectures.
__typeof
__typeof
is syntactically equivalent to sizeof, but its result is of
type int and is a number representing the type of its argument.
This may be necessary for implementing `stdarg.h'.
__alignof
__alignof
is syntactically equivalent to sizeof, but its result is of
type int and is the alignment in bytes of the type of the argument.
This may be necessary for implementing `stdarg.h'.
__offsetof
__offsetof
is a builtin version of the offsetof
-macro
as defined in the C language. The first argument is a structure
type and the second a member of the structure type. The result
will be a constant expression representing the offset of the
specified member in the structure.
Only use if you know what you are doing!
When optimizing and generating code, vbcc
often has to take
into account side-effects of function-calls, e.g. which registers might
be modified by this function and what variables are read or modified.
A rather imprecise way to make assumptions on side-effects is given by the ABI of a certain system (that defines which registers have to be preserved by functions) or rules derived from the language (e.g. local variables whose address has not been taken cannot be accessed by another function).
On higher optimization levels (see section 3.4.15 Inter-Procedural Analysis and
see section 3.4.16 Cross-Module Optimizations)) vbcc
will try to analyse
functions and often gets much more precise informations regarding
side-effects.
However, if the source code of functions is not visible to vbcc
,
e.g. because the functions are from libraries or they are
written in assembly (see section 3.5.3 Inline-Assembly Functions), it is obviously
not possible to analyze the code. In this case, it is possible to specify
these side-effects using the following special variable-attributes
(see section 3.5.4 Variable Attributes).
The __regsused(<register-list>)
attribute specifies the registers
used or modified by a function. The register list is a list of register
names (as defined in the backend-documentation) separated by slashes and
enclosed in double-quotes, e.g.
__regsused("d0/d1") int abs();
declares a function abs
which only uses registers d0
and
d1
.
__varsmodified(<variable-list>)
specifies a list of variables with
external linkage
which are modified by the function. __varsused
is similar, but
specifies the external variables read by the function. If a variable is
read and written, both attributes have to be specified. The variable-list
ist a list of identifiers, separated by slashes and enclosed in double
quotes.
The attribute __writesmem(<type>)
is used to specify that the
function accesses memory using a certain type. This is necessary if the
function modifies memory accessible to the calling function which cannot
be specified using __varsmodified
(e.g. because it is accessed via
pointers). __readsmem
is similar, but specifies memory which is
read.
If one of __varsused
, varsmodified
, __readsmem
and
__writesmem
is specified, all relevant side-effects must be
specified. If, for example, only __varsused("my_global")
is specified, this implies that the function only reads my_global
and does not modify any variable accessible to the caller.
All of these attributes may be specified multiple times.
Some known target-independent problems of vbcc
at the moment:
volatile
is sometimes ignored by the optimizer.
All those who wrote parts of the vbcc
distribution, made suggestions,
answered my questions, tested vbcc
, reported errors or were otherwise
involved in the development of vbcc
(in descending alphabetical order,
under work, not complete):
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |